﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Flurl.Http;
using Pay.Core;
using Pay.Core.WeiXin;
using Pay.DTO;
using Pay.IService;
using Pay.TO;
using Senparc.CO2NET.Extensions;

namespace Pay.Service {
    public class TwPayService : ServiceBase2, IPayService, IDisposable {
        private ISettingService _iSettingService;
        private IMerchantService _iMerchantService;
        private IChargeService _iChargeService;
        private IPayHtmlService _iPayHtmlService;
        private IOrderService _iOrderService;
        private IPayNotifyService _iPayNotifyService;
        public TwPayService(IUnitOfWork iUnitOfWork, ISettingService iSettingService,
                            IMerchantService iMerchantService, IChargeService iChargeService,
                             IPayHtmlService iPayHtmlService, IOrderService iOrderService,
                                     IPayNotifyService iPayNotifyService) : base(iUnitOfWork) {
            _iSettingService = iSettingService;
            _iMerchantService = iMerchantService;
            _iChargeService = iChargeService;
            _iPayHtmlService = iPayHtmlService;
            _iOrderService = iOrderService;
            _iPayNotifyService = iPayNotifyService;
        }

        public Task<transfer_result> AgencyFund(apply_receive model) {
            throw new NotImplementedException();
        }

        public Task<certify_verify_result> CertifyVerify(certify_verify model) {
            throw new NotImplementedException();
        }

        public int DealItp(long id) {
            throw new NotImplementedException();
        }

        public Task<gateway_pay_result> GatewayPay(gateway_pay_model model) {
            throw new NotImplementedException();
        }

        public List<type_setting> GatewayPayBank() {
            throw new NotImplementedException();
        }

        public Task<pay_notity> GatewayPayQuery(refund_model_query model) {
            throw new NotImplementedException();
        }

        public Task<refund_result> GatewayPayRefund(refund_model model) {
            throw new NotImplementedException();
        }

        public Task<refund_result> GatewayRefundQuery(refund_model_query model) {
            throw new NotImplementedException();
        }

        public Task<ApiResultMessage> InsteadReceive(verify_model_sms model) {
            throw new NotImplementedException();
        }

        public Task<ApiResultMessage> InsteadReceive(verify_model model) {
            throw new NotImplementedException();
        }

        public Task<int> ItpToFile(DateTime create_date) {
            throw new NotImplementedException();
        }

        public async Task<mall_result> MallPay(mall_model model) {
            var log = IocHelper.Get<ILogHelper>("info");
            //限制同一个用户频繁支付
            string cache_value = CacheHelper.Get<string>(model.bind_no);
            if (string.IsNullOrEmpty(cache_value)) {
                CacheHelper.Set(model.bind_no, model.bind_no, 5);
            } else {
                return new mall_result { order_no = model.order_no };
            }
#if DEBUG
            var notfiy_success = string.Format("http://{0}/pay/h5_pay_notify?order_no={1}", "192.168.10.127", model.order_no);
            var result_success = await notfiy_success.GetAsync().ReceiveString();
#endif
			if (!string.IsNullOrEmpty(model.body)) {
				if (model.body.Length > 40) {
					model.body = model.body.Substring(0, 30) + "...";
					log.Info(model.body);
				}
			}

            string ip = model.openid;
            string openId = null;
            var timeStamp = TenPayV3Util.GetTimestamp();
            var nonceStr = TenPayV3Util.GetNoncestr();
            int totalFee = (int)Decimal.Parse(model.tran_amount);
            var xmlDataInfo = new TenPayV3UnifiedorderRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, model.body, model.order_no,
                                                                  totalFee, ip, model.notify, TenPayV3Type.MWEB, openId,
                                                                  TenPayV3Info.Key, nonceStr, "", null, null, null, model.order_no);
            try {
                if (model.is_wx_pub_account_pay) {//微信公众号支付
                    unifiedorder jsResult = await TenPayV3.Unifiedorder(new payment_query() { app_id = TenPayV3Info.AppId, app_secret = TenPayV3Info.AppSecret, key = TenPayV3Info.Key, mchid = TenPayV3Info.MchId, attach = model.order_no },
                                                   model.openid, model.body, model.order_no, totalFee.ToString(), model.notify);
                    log.Info("微信公众号支付：" + jsResult.ToJson());
                    var data = new mall_result { order_no = model.order_no, pay_info = jsResult.ToJson() };
                    return ApiResultToJson.Json(data);
                } else {//H5支付
                    UnifiedorderResult h5Result = TenPayV3.Html5Order(xmlDataInfo);
                    log.Info(h5Result.ToJson());
                    var mwebUrl = h5Result.mweb_url;
                    if (!string.IsNullOrEmpty(mwebUrl)) {
                        if (model.req_method == 2)
                            mwebUrl += string.Format("&redirect_url={0}", model.front_notify.AsUrlData());
                        var data = new mall_result { order_no = model.order_no, code_url = mwebUrl };
                        return ApiResultToJson.Json(data);
                    }
                }
            }
            catch (Exception ex) {
                log.Info(ex.Message);
            }
            return await ApiResultToJson.JsonAsync<mall_result>("h5支付失败");
        }

        public Task<merchant_register_result> MerchantModify(long bind_id, string settle_type, PayChannel channel = PayChannel.None) {
            throw new NotImplementedException();
        }

        public Task<merchant_register_result> MerchantRegister(merchant_register_model dto, string opt) {
            throw new NotImplementedException();
        }

        public Task<merchant_register_result> MerchantRegister(long bind_id, string settle_type, PayChannel channel = PayChannel.None) {
            throw new NotImplementedException();
        }

        public async Task<native_result> NativePay(native_model model) {
            var log = IocHelper.Get<ILogHelper>("info");
            var setting = _iSettingService.Get();
            var merchant = _iMerchantService.Get(model.merchant_no);
            //把商户请求转为通道请求消息
            var id = Guid.NewGuid().ToString("N");
            var notifyUrl = model.notify;
            if (string.IsNullOrEmpty(notifyUrl))
                notifyUrl = setting.site.api_url + "/h5_native_notify/" + id;
            else if (notifyUrl.Contains(t_RequestMethod.TOKEN_USER_UPGRADE_NOTIFY))
                notifyUrl = model.notify + id;

            //下单时间
            string orderDateTime = DateTime.Now.ToString("yyyyMMddHHmmss");
            var charge = model.ToDtoObject<charge_dto>();
            charge.status = ChargeStatus.WaitPay;
            charge.bind_id = _iMerchantService.Get(charge.bind_no).id;
            var order_html = new pay_html_dto {
                id = id,
                html = model.ToJson(),
                merchant_no = model.merchant_no,
                order_no = model.order_no,
                charge = charge.ToJson(),
                create_time = orderDateTime.ToDateTime(),
                pay_type = "2"
            };

            string v_oid = order_html.id;
            var payHtml = _iPayHtmlService.Get(order_html.merchant_no, order_html.order_no);
            if (payHtml == null) {
                _iPayHtmlService.Save(order_html);
            } else {
                v_oid = payHtml.id;
                if (string.IsNullOrEmpty(notifyUrl))
                    notifyUrl = setting.site.api_url + "/h5_native_notify/" + payHtml.id;
                else if (notifyUrl.Contains(t_RequestMethod.TOKEN_USER_UPGRADE_NOTIFY))
                    notifyUrl = model.notify + payHtml.id;
            }
#if DEBUG
            var notfiy_success = string.Format("{0}/token_upgrade_pay_success/{1}", _iSettingService.Get().site.api_url, v_oid);
            var result_success = await notfiy_success.GetAsync().ReceiveString();
#endif
            string ip = model.openid;
            string openId = null;
            var timeStamp = TenPayV3Util.GetTimestamp();
            var nonceStr = TenPayV3Util.GetNoncestr();
            int totalFee = (int)Decimal.Parse(model.tran_amount);
            model.notify = notifyUrl;
            string out_trade_no = DtoHelper.GenerateOrderNumber();
            var xmlDataInfo = new TenPayV3UnifiedorderRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, model.body, out_trade_no,
                                                                  totalFee, ip, model.notify, TenPayV3Type.MWEB, openId,
                                                                  TenPayV3Info.Key, nonceStr, "", null, null, null, v_oid);
            try {
                if (model.is_wx_pub_account_pay) {//微信公众号支付
                    unifiedorder jsResult = await TenPayV3.Unifiedorder(new payment_query() { app_id = TenPayV3Info.AppId, app_secret = TenPayV3Info.AppSecret, key = TenPayV3Info.Key, mchid = TenPayV3Info.MchId, attach = v_oid },
                                                   model.openid, model.body, out_trade_no, totalFee.ToString(), model.notify);
                    log.Info("微信公众号支付：" + jsResult.ToJson());
                    var data = new native_result { order_no = model.order_no, pay_info = jsResult.ToJson() };
                    return ApiResultToJson.Json(data);
                } else {//H5支付
                    UnifiedorderResult h5Result = TenPayV3.Html5Order(xmlDataInfo);
                    log.Info(h5Result.ToJson());
                    var mwebUrl = h5Result.mweb_url;
                    if (!string.IsNullOrEmpty(mwebUrl)) {
                        mwebUrl += string.Format("&redirect_url={0}", model.front_notify.AsUrlData());
                        var data = new native_result { order_no = model.order_no, code_url = mwebUrl };
                        return ApiResultToJson.Json(data);
                    }

                }
            }
            catch (Exception ex) {
                log.Info(ex.Message);
            }

            return await ApiResultToJson.JsonAsync<native_result>("h5支付失败");
        }

        public async Task<string> Notify(string merchant_no, string order_no) {
            string result = string.Empty;
            charge_dto order = _iChargeService.Get(merchant_no, order_no);
            try {
                var data = new pay_notity {
                    tran_amount = ((int)(order.order_amount * 100)).ToString(),
                    order_no = order.order_no,
                    transaction_no = order.pay_info.transaction_no,
                    pay_time = order.pay_info.pay_time.HasValue ? order.pay_info.pay_time.Value : order.order_time,
                    status = (order.status == ChargeStatus.Finish ? 1 : 2)
                };
                data.result_msg = (data.status == 1 ? "支付成功" : order.fail);
                if (string.IsNullOrEmpty(order.notify)) return "OK";
                var notify_result = await order.notify.PostJsonAsync(ApiResultToJson.Json(data)).ReceiveJson<ResultMessage<string>>();
                result = notify_result.data;
                var log = IocHelper.Get<ILogHelper>("info");
                log.Info(order.order_no + ":" + notify_result.ToJson());
            }
            catch (Exception ex) {
                var log = IocHelper.Get<ILogHelper>("info");
                log.Error("订单通道查询异常:" + order.order_no);
                string message = string.Format("消息类型：{0}\r\n消息内容：{1}\r\n引发异常的方法：{2}\r\n引发异常源：{3}"
                                , ex.GetType().Name, ex.Message, ex.TargetSite, ex.Source + ex.StackTrace);
                log.Error(message);
            }
            return result;
        }

        public Task<string> NotifyTransfer(string merchant_no, string order_no) {
            throw new NotImplementedException();
        }

        public Task<quick_pay_result> QuickPay(quick_sms_model model) {
            throw new NotImplementedException();
        }

        public Task<quick_pay_result> QuickPay(quick_pay_model model) {
            throw new NotImplementedException();
        }

        public Task<pay_notity> QuickPayQuery(refund_model_query model) {
            throw new NotImplementedException();
        }

        public Task<refund_result> QuickPayRefund(refund_model model) {
            throw new NotImplementedException();
        }

        public Task<refund_result> QuickPayRefundQuery(refund_model_query model) {
            throw new NotImplementedException();
        }

        public Task<ApiResultMessage> QuickPaySendsms(quick_sendsms_model model) {
            throw new NotImplementedException();
        }

        public Task<quota_result> Quota(string merchant_no, string busiType) {
            throw new NotImplementedException();
        }

        public Task<transfer_result> ReTransfer(long id) {
            throw new NotImplementedException();
        }

        public Task<transfer_result> TokenTransfer(long id) {
            throw new NotImplementedException();
        }

        public Task<transfer_result> TokenTransferQuery(transfer_query model) {
            throw new NotImplementedException();
        }

        public Task<batch_transfer_result> Transfer(batch_transfer model) {
            throw new NotImplementedException();
        }

        public Task<transfer_result> Transfer(apply_transfer model) {
            throw new NotImplementedException();
        }

        public Task<int> TransferBack(long batchId, string noticeTranId, long merchant_id) {
            throw new NotImplementedException();
        }

        public Task<int> TransferNotify(long batchId, string batchFileName, long merchant_id) {
            throw new NotImplementedException();
        }

        public Task<transfer_result> TransferQuery(transfer_query model) {
            throw new NotImplementedException();
        }
    }
}
